import pygame
import math
import Util
import Text
import Graphics
import Config
import Vector
import Wireframe
import G

smallfont = Text.font(size=int(10 * Config.width/800.0))
font = Text.font(size=int(12 * Config.width/800.0))
scorefont = Text.font(size=int(20 * Config.width/800.0))

scorecolor = (255,255,128)
moneycolor = (128,255,128)
healthcolor = (255,50,50)
shieldcolor = (50,50,255)
energycolor = (50,255,50)
generationcolor = (220,220,80)
draincolor = (80,220,220)
invincibilitycolor = (255,255,255)

#Note: HUD bar is in 1:3 ratio
positions = {'scorerect': (0.05, 0.00, 0.9, 0.2),
             'wireframerect': (0.0, 0.22, 1.0, 0.7),
             'shieldgaugerect': (0.1, 1.0, 0.8, 0.8),
             'generationgaugerect': (0.1, 1.9, 0.15, 0.7),
             'energygaugerect': (0.3, 1.9, 0.4, 0.7),
             'draingaugerect': (0.75, 1.9, 0.15, 0.7)}

class HUD(object):
   __slots__ = ('window',
                'screen',
                'rect',
                'topleft',
                'scorerect',
                'wireframerect',
                'shieldgaugerect',
                'shieldgaugerectinner',
                'healthgaugerect',
                'energygaugerect',
                'generationgaugerect',
                'healthcolor',
                'shieldcolor',
                'energycolor',
                'draincolor',
                'generationcolor',
                'draingaugerect',
                'shieldtextrect',
                'healthtextrect',
                'energytextrect',
                'generationtextrect',
                'draintextrect',
                'arcwidth',
                'weaponicons',
                'ship',
                'wireframe',
                'maxHP',
                'maxshield',
                'maxenergy',
                'lastscore',
                'lastmoney',
                'lastHP',
                'lastshield',
                'lastgeneration',
                'lastdrain',
                'lastenergy',
                'lastammocounts',
                'redraw')
   
   def __init__(self, window, gamescreen, ship):
      self.window = window
      rect = gamescreen.get_rect()
      self.screen = pygame.Surface((rect.width/4, rect.height))
      self.rect = self.screen.get_rect()
      self.topleft = (rect.width, 0)
      def c(x, y, a, b):
         return pygame.Rect(int(self.rect.width*x), int(self.rect.width*y),
                            int(self.rect.width*a), int(self.rect.width*b))
      for key, value in positions.items():
         setattr(self, key, c(*value))
      w,h = self.shieldgaugerect.size
      self.shieldgaugerectinner = self.shieldgaugerect.inflate(w * -3/24,
                                                               h * -3/24)\
                                                       .move(0, h/24)                                        
      self.healthgaugerect = self.shieldgaugerectinner.inflate(w*-3/8, h*-3/8)
      self.arcwidth = self.shieldgaugerect.width/6
      self.ship = ship
      wireframesize = map(int, Vector.s_mult(self.wireframerect.size, 0.9))
      self.wireframe = Wireframe.Wireframe(self.ship, wireframesize, color=(0,255,0))
      G.HUD.add(self.wireframe)
      self.wireframe.rect.center = self.wireframerect.center
      self.wireframe.rect.left += self.topleft[0]
      self.lastscore = None
      self.lastmoney = None
      self.lastHP = None
      self.lastshield = None
      self.lastgeneration = None
      self.lastdrain = None
      self.lastenergy = None
      self.lastammocounts = None
      self.healthtextrect = None
      self.shieldtextrect = None
      self.energytextrect = None
      self.generationtextrect = None
      self.draintextrect = None
      self.redraw = False
      self.healthcolor = healthcolor
      self.shieldcolor = shieldcolor
      self.energycolor = energycolor
      self.generationcolor = generationcolor
      self.draincolor = draincolor
      self.recalculate()
   
   def draw(self):
      score = self.ship.score
      money = self.ship.money
      shieldHP = self.shieldHP()
      shipHP = self.ship.HP
      generation = self.ship.energy_generation()
      drain = self.ship.energy_drain()
      energy = self.energy()
      ammocounts = self.wireframe.getammocounts()
      
      if score != self.lastscore or money != self.lastmoney or self.redraw:
         self.lastscore = score
         self.lastmoney = money
         self.drawscore(score, money)
      
      if shipHP != self.lastHP or shieldHP != self.lastshield or self.redraw:
         self.lastHP = shipHP
         self.lastshield = shieldHP
         self.drawhealthgauges(shipHP, shieldHP)
      
      if generation != self.lastgeneration or self.redraw:
         self.lastgeneration = generation
         self.drawgenerationgauge(generation)
      
      if drain != self.lastdrain or self.redraw:
         self.lastdrain = drain
         self.drawdraingauge(drain)
      
      if energy != self.lastenergy or self.redraw:
         self.lastenergy = energy
         self.drawenergygauge(energy)
      
      if ammocounts != self.lastammocounts or self.redraw:
         self.lastammocounts = ammocounts
         self.wireframe.drawammocounts(ammocounts)
      
      self.redraw = False
      pygame.draw.rect(self.screen, (255,255,255), self.rect, 1)
      self.window.blit(self.screen, self.topleft)
   
   def drawscore(self, score, money):
      pygame.draw.rect(self.screen, (0,0,0), self.scorerect)
      mes = scorefont.render("%s" % str(score).zfill(15), 1, scorecolor)
      Graphics.blit_anchored(self.screen, mes, self.scorerect.topright, 'topright')
      mes = scorefont.render("%s" % str(money).zfill(15), 1, moneycolor)
      Graphics.blit_anchored(self.screen, mes, self.scorerect.bottomright, 'bottomright')
   
   def drawhealthgauges(self, HP, shield):
      pygame.draw.rect(self.screen, (0,0,0), self.shieldgaugerect)
      self.drawHPgauge(HP)
      self.drawshieldgauge(shield)
   
   def drawHPgauge(self, HP):
      proportionempty = Util.constrain(1.0 - 1.0 * HP / self.maxHP, 0.0, 0.999)
      pygame.draw.arc(self.screen, self.healthcolor, self.healthgaugerect,
                      math.pi/2 + 2 * proportionempty * math.pi, 5*math.pi/2, 
                      self.arcwidth)
      if self.healthtextrect is not None:
         pygame.draw.rect(self.screen, (0,0,0), self.healthtextrect)
      mes = font.render("%d/%d" % (HP, self.maxHP), 1, healthcolor, (0,0,0))
      mes.set_colorkey((0,0,0))
      self.healthtextrect = Graphics.blit_anchored(self.screen, mes, 
            (self.rect.right-5, 
             self.shieldgaugerect.top-2), 
             'topright')
   
   def drawshieldgauge(self, shield):
      if shield is None:
         return
      proportionempty = Util.constrain(1.0 - 1.0 * shield / self.maxshield, 0.0, 0.999)
      pygame.draw.arc(self.screen, self.shieldcolor, self.shieldgaugerectinner,
                      math.pi/2 + 2 * proportionempty * math.pi, 5*math.pi/2, 
                      self.arcwidth)
      if self.shieldtextrect is not None:
         pygame.draw.rect(self.screen, (0,0,0), self.shieldtextrect)
      mes = font.render("%d/%d" % (shield, self.maxshield), 1, shieldcolor, (0,0,0))
      mes.set_colorkey((0,0,0))
      self.shieldtextrect = Graphics.blit_anchored(self.screen, mes, (self.shieldgaugerect.left + int(self.shieldgaugerect.width*0.5), 
                                                 self.shieldgaugerect.top-2), 
                                                 'topright')
   
   def drawgenerationgauge(self, gen):
      if self.maxenergy == 0:
         return
      pygame.draw.rect(self.screen, (0,0,0), self.generationgaugerect)
      proportionempty = Util.constrain(1.0 - 1.0 * gen / self.maxenergy, 0.0, 1.0)
      proportionfull = 1.0 - proportionempty
      drawrect = pygame.Rect(self.generationgaugerect.left,
                             self.generationgaugerect.top + self.generationgaugerect.height * proportionempty,
                             self.generationgaugerect.width,
                             self.generationgaugerect.height * proportionfull)
      pygame.draw.rect(self.screen, self.generationcolor, drawrect)
      pygame.draw.rect(self.screen, (255,255,255), self.generationgaugerect, 1)
      if self.generationtextrect is not None:
         pygame.draw.rect(self.screen, (0,0,0), self.generationtextrect)
      mes = font.render("%.1f" % gen, 1, generationcolor, (0,0,0))
      mes.set_colorkey((0,0,0))
      self.generationtextrect = Graphics.blit_anchored(self.screen, mes, (self.generationgaugerect.right, 
                                                 self.generationgaugerect.top), 
                                                 'bottomright')
      
   def drawdraingauge(self, drain):
      if self.maxenergy == 0:
         return
      pygame.draw.rect(self.screen, (0,0,0), self.draingaugerect)
      proportionempty = Util.constrain(1.0 - 1.0 * drain / self.maxenergy, 0.0, 1.0)
      proportionfull = 1.0 - proportionempty
      drawrect = pygame.Rect(self.draingaugerect.left,
                             self.draingaugerect.top + self.draingaugerect.height * proportionempty,
                             self.draingaugerect.width,
                             self.draingaugerect.height * proportionfull)
      pygame.draw.rect(self.screen, self.draincolor, drawrect)
      pygame.draw.rect(self.screen, (255,255,255), self.draingaugerect, 1)
      if self.draintextrect is not None:
         pygame.draw.rect(self.screen, (0,0,0), self.draintextrect)
      mes = font.render("%.1f" % drain, 1, draincolor, (0,0,0))
      mes.set_colorkey((0,0,0))
      self.draintextrect = Graphics.blit_anchored(self.screen, mes, (self.draingaugerect.right, 
                                                 self.draingaugerect.top), 
                                                 'bottomright')
   
   def drawenergygauge(self, energy):
      if self.maxenergy == 0:
         return
      pygame.draw.rect(self.screen, (0,0,0), self.energygaugerect)
      proportionempty = Util.constrain(1.0 - 1.0 * energy / self.maxenergy, 0.0, 1.0)
      proportionfull = 1.0 - proportionempty
      drawrect = pygame.Rect(self.energygaugerect.left,
                             self.energygaugerect.top + self.energygaugerect.height * proportionempty,
                             self.energygaugerect.width,
                             self.energygaugerect.height * proportionfull)
      pygame.draw.rect(self.screen, self.energycolor, drawrect)
      pygame.draw.rect(self.screen, (255,255,255), self.energygaugerect, 1)
      if self.energytextrect is not None:
         pygame.draw.rect(self.screen, (0,0,0), self.energytextrect)
      mes = font.render("%.0f/%.0f" % (energy, float(self.maxenergy)), 1, energycolor, (0,0,0))
      mes.set_colorkey((0,0,0))
      self.energytextrect = Graphics.blit_anchored(self.screen, mes, (self.energygaugerect.right, 
                                                 self.energygaugerect.top), 
                                                 'bottomright')
   
   def energy(self):
      if self.ship.generator is not None:
         return self.ship.generator.reserve
      else:
         return 0.0
   
   def recalculate(self, ship=None):
      if ship is not None:
         self.ship = ship
      self.maxHP = self.ship.health
      if self.ship.shield is not None:
         self.maxshield = self.ship.shield.health
      else:
         self.maxshield = 0
      if self.ship.generator is not None:
         self.maxenergy = self.ship.generator.capacity
      else:
         self.maxenergy = 0
      self.wireframe.update()
   
   def refresh(self):
      self.redraw = True
   
   def shieldHP(self):
      if self.ship.shield is not None:
         return self.ship.shield.HP
      else:
         return None
